// 070731;080305 alexch
//
// ==========  This file is under  LGPL, the GNU Lesser General Public Licence
// ==========  Dialing Lemmatizer (www.aot.ru)
// ==========  Copyright by Alexey Sokirko 
//
// ==========  Visual Studio project for 32/64 bit DLL-wrapper
// ==========  Created by Hulbee AG

#ifndef __STLSYSF_H_
#define __STLSYSF_H_

#pragma warning(disable: 4786)
#include <string>
#include <vector>
#include <map>
#include <set>

#ifndef ARRAY_COUNT
	#define ARRAY_COUNT(x) (sizeof(x) / sizeof((x)[0]))
#endif

#ifndef ARRAY_HIGH
	#define ARRAY_HIGH(x) (sizeof(x) / sizeof((x)[0]) - 1)
#endif

namespace StlFunc {

typedef unsigned int uint;
typedef unsigned __int64 uint64;
typedef std::string str_t;
typedef std::wstring wstr_t;
typedef std::vector<std::string> strvec_t;
typedef std::vector<std::string>::iterator strvec_it;
typedef std::vector<std::string>::const_iterator strvec_cit;
typedef std::vector<std::wstring> wstrvec_t;
typedef std::vector<std::wstring>::iterator wstrvec_it;
typedef std::vector<std::wstring>::const_iterator wstrvec_cit;
typedef std::set<std::string> strset_t;
typedef std::set<std::wstring> wstrset_t;

extern uint MaxStackAlloc;

str_t& SetStr(str_t &dst, const char *src, int maxLen);
wstr_t& SetStr(wstr_t &dst, const wchar_t *src, int maxLen);

str_t Str(const char *src, int maxLen);
wstr_t Str(const wchar_t *src, int maxLen);

bool GetStr(char *dst, int maxLen, const str_t &src);
bool GetStr(wchar_t *dst, int maxLen, const wstr_t &src);
/* copy characters from 'src' to 'dst'; maximum 'dst' size is 'maxLen' characters (including trailing 0)
   returns 'true' if 'dst' was large enough to hold all characters of 'src' and 'false' otherwise
   (in this case the maximum possible number of characters will be copied) */

wstr_t& Str2W(const str_t &src, wstr_t &dst);
wstr_t Str2W(const str_t &src);

str_t& W2Str(const wstr_t &src, str_t &dst, char defChar = '?');
str_t W2Str(const wstr_t &src, char defChar = '?');

bool W2Utf8(wchar_t w, char *dest, const char *limit);
str_t& W2Utf8(str_t &dst, const wchar_t *src, size_t len);
str_t& W2Utf8(str_t &dst, const wstr_t &src);
str_t W2Utf8(const wstr_t &src);

bool AsciiW2Str(const wstr_t &src, str_t &dst);
bool AsciiW2Str(const wchar_t *src, str_t &dst);
// 'src' should contain only ASCII characters (i.e. it should not contain characters with codes > 0x7f)!
// returns 'false' if the condition above is not satisfied

str_t& AsciiUpper(str_t &s);
wstr_t& AsciiUpper(wstr_t &s);

str_t& AsciiLower(str_t &s);
wstr_t& AsciiLower(wstr_t &s);

bool IsAscii(const char *s);
bool IsAscii(const wchar_t *s);

char LastChar(const str_t &s);
wchar_t LastChar(const wstr_t &s);

str_t& EraseLastIf(str_t &s, char to_erase);
wstr_t& EraseLastIf(wstr_t &s, wchar_t to_erase);

bool EndsWith(const str_t &s, const char *tail);
bool EndsWith(const wstr_t &s, const wchar_t *tail);

wstr_t& CloseSentence(wstr_t &s);

const size_t MaxPrintfChars = 32768;

bool StrPrintf(str_t &dst, const char *fmt, ...);
bool StrPrintf(wstr_t &dst, const wchar_t *fmt, ...);
str_t StrPrintf(const char *fmt, ...);
wstr_t StrPrintf(const wchar_t *fmt, ...);
bool StrVPrintf(str_t &dst, const char *fmt, va_list va);
bool StrVPrintf(wstr_t &dst, const wchar_t *fmt, va_list va);

bool Str2Int(const str_t &src, int &val);
bool Str2Int(const wstr_t &src, int &val);
bool Str2Int(const str_t &src, __int64 &val);
bool Str2Int(const wstr_t &src, __int64 &val);

bool HexStr2UInt(const str_t &src, uint &val);
bool HexStr2UInt(const wstr_t &src, uint &val);
bool HexStr2UInt(const str_t &src, uint64 &val);
bool HexStr2UInt(const wstr_t &src, uint64 &val);

str_t& TrimRight(str_t &s);
wstr_t& TrimRight(wstr_t &s);
// removes trailing spaces and ctrl characters from 's'

str_t& TrimLeft(str_t &s);
wstr_t& TrimLeft(wstr_t &s);
// removes leading spaces and ctrl characters from 's'

str_t& Trim(str_t &s);
wstr_t& Trim(wstr_t &s);
// removes leading and trailing spaces and ctrl characters from 's'

str_t& PadRight(str_t &s, size_t len, char c);
wstr_t& PadRight(wstr_t &s, size_t len, wchar_t c);
// if (s.length() < len) then appends characters 'c' to 's' until (s.length() == len)

str_t& ReplaceChar(str_t &s, char from, char to);
wstr_t& ReplaceChar(wstr_t &s, wchar_t from, wchar_t to);

str_t ReplaceStr(const str_t &s, const str_t &from, const str_t &to);
wstr_t ReplaceStr(const wstr_t &s, const wstr_t &from, const wstr_t &to);

str_t& Data2StrHex(unsigned char *data, unsigned int dataSize, str_t &s);
str_t Data2StrHex(unsigned char *data, unsigned int dataSize);

str_t& FormatHoursMinSec(str_t &stime, unsigned int sec);

typedef int __cdecl CmpFunc(const wchar_t *string1, const wchar_t *string2);

class CommandLineParser {
protected:
	CmpFunc *m_cmp;
	std::vector<wstr_t> m_param, m_simple, m_option_key, m_option_value;
	std::vector<uint> m_option_key_index;
	void ProcessParam(wstr_t &w, int &paramIndex, int fromIndex);
public:
	wstr_t Prefixes, ParamDelims, ValueDelims;
	CommandLineParser(bool caseSensitive = false, const wchar_t *prefixes = L"/-",
		const wchar_t *paramDelims = L" \x9\n\r", const wchar_t *valueDelims = L":=");
	void Parse(const wchar_t *commandLine, uint fromIndex = 0,
		bool quotesDoubling = false, bool quotesAreDelimiters = true);
	size_t ParamCount()
	{
		return m_param.size();
	}
	wstr_t& ParamStr(uint i, wstr_t &value);
	const wchar_t* ParamStr(uint i);
	// i = 0..ParamCount() - 1
	size_t SimpleParamCount()
	{
		return m_simple.size();
	}
	wstr_t& SimpleParamStr(uint i, wstr_t &value);
	const wchar_t* SimpleParamStr(uint i);
	size_t OptionCount()
	{
	  return m_option_key.size();
	}
	wstr_t& OptionStr(uint i, wstr_t &value);
	const wchar_t* OptionStr(uint i);
	// 'OptionStr' returns complete i-th option string (including the option prefix, etc.)
	wstr_t& OptionKey(uint i, wstr_t &value);
	const wchar_t* OptionKey(uint i);
	// 'OptionKey' returns i-th option key (without the option prefix or value)
	int FindOption(const wchar_t *optionName);
	bool HasOption(const wchar_t *optionName) { return FindOption(optionName) >= 0; }
	bool RemoveOption(const wchar_t *optionName);
	wstr_t& OptionValue(const wchar_t *optionName, wstr_t &value, bool remove = false);
	wstr_t OptionValue(const wchar_t *optionName, bool remove = false)
	{
		wstr_t value;
		return OptionValue(optionName, value, remove);
	}
	bool OptionValue(const wchar_t *optionName, int &value, bool remove = false);
};

class Ini {
protected:
	bool m_caseSens;
	wstr_t m_def_sec;
	virtual void Upcase(wstr_t &w);
	wstr_t& Normalize(wstr_t &w)
	{
		if (!m_caseSens)
			Upcase(w);
		return w;
	}
	virtual bool FGetStr(const wchar_t *sectionName, const wchar_t *keyName, wstr_t &value) = 0;
public:
	Ini(bool caseSensitive = false): m_caseSens(caseSensitive) {}
	bool GetStr(const wchar_t *sectionName, const wchar_t *keyName, wstr_t &value)
	{
		return FGetStr(sectionName, keyName, value);
	}
	void SetDefaultSection(const wchar_t *sectionName);
	bool GetStr(const wchar_t *keyName, wstr_t &value)
	{
		return FGetStr(m_def_sec.c_str(), keyName, value);
	}
	// 'sectionName' can be empty
	bool GetBool(const wchar_t *sectionName, const wchar_t *keyName, bool &value);
	bool GetBool(const wchar_t *keyName, bool &value)
	{
		return GetBool(m_def_sec.c_str(), keyName, value);
	}
	bool GetInt(const wchar_t *sectionName, const wchar_t *keyName, int &value);
	bool GetInt(const wchar_t *keyName, int &value)
	{
		return GetInt(m_def_sec.c_str(), keyName, value);
	}
};

class MemIni: public Ini {
protected:
	std::vector<wstr_t> m_sections;
	typedef std::vector<wstr_t>::iterator sec_iter_t;
	typedef std::map<wstr_t, wstr_t> key_value_map_t;
	typedef std::vector<key_value_map_t*> sec_map_vec_t;
	typedef sec_map_vec_t::iterator sec_map_vec_iter_t;
	sec_map_vec_t m_sec_map_vec;
	virtual bool FGetStr(const wchar_t *sectionName, const wchar_t *keyName, wstr_t &value);
	void Clear();
	bool AddLine(const wchar_t *line, const wchar_t *line_end, wstr_t &section);
public:
	MemIni(bool caseSensitive = false): Ini(caseSensitive) {}
	virtual ~MemIni();
	bool Parse(const void *mem, uint byteSize);
	// returns 'true' if parsed successfully or 'false' if some errors were found
};

} // StlFunc

#endif
